package com.boom.springapp.javafxdemo.controller;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import com.boom.springapp.javafxdemo.common.CommentOrder;
import com.boom.springapp.javafxdemo.common.DefaultConfiguration;
import com.boom.springapp.javafxdemo.common.MemoryHolder;
import com.boom.springapp.javafxdemo.common.VideoOrder;
import com.google.zxing.BarcodeFormat;
import com.google.zxing.EncodeHintType;
import com.google.zxing.MultiFormatWriter;
import com.google.zxing.client.j2se.MatrixToImageWriter;
import com.google.zxing.common.BitMatrix;
import javafx.application.Platform;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.DirectoryChooser;
import javafx.stage.Stage;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.net.URI;
import java.net.URL;
import java.net.http.HttpClient;
import java.net.http.HttpRequest;
import java.net.http.HttpResponse;
import java.time.Duration;
import java.util.HashMap;
import java.util.Map;
import java.util.Optional;
import java.util.ResourceBundle;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

/**
 * @author hhl
 * @version 1.0
 * @description
 * @date 2025/11/18 23:32
 */
@Slf4j
@Component
public class SettingsController implements Initializable {
    public TextArea cookieInput;
    public Button qrCodeButton;
    public TextField filePathField;
    public Button browseButton;
    public RadioButton timeRadioButton;
    @FXML
    public ToggleGroup commentOrderToggleGroup;
    @FXML
    public ToggleGroup videoOrderToggleGroup;
    public RadioButton likeRadioButton;
    public RadioButton replyRadioButton;
    public RadioButton publishTimeRadioButton;
    public RadioButton playCountRadioButton;
    public RadioButton collectCountRadioButton;
    public CheckBox defaultMapCheckBox;
    public CheckBox defaultDownloadImageCheckBox;
    public Spinner minDelaySpinner;
    public Spinner maxDelaySpinner;
    public Spinner retryDelaySpinner;
    public Spinner retryCountSpinner;
    public Button saveButton;
    public Button resetButton;
    public Spinner emptyPageLimitSpinner;


    @Autowired
    private DefaultConfiguration defaultConfiguration;


    /**
     * 默认输出目录
     */
    private String defaultOutputPath;

    /**
     * -- SETTER --
     * 设置主窗口引用，用于对话框定位
     *
     * @param stage 主窗口
     */
    @Setter
    private Stage primaryStage;

    private Stage qrStage;

    private Label qrLabel;


    private ExecutorService executor;
    private HttpClient httpClient = HttpClient.newHttpClient();

    private boolean polling = false;

    String qrcodeUrl;

    String qrcodeKey;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        initDefaultConfig();
        // 初始化扫码登录按钮事件，点击按钮弹出二维码页面，并且有一个按钮，可以点击刷新二维码
        qrCodeButton.setOnAction(event -> showQrCodeDialog());
        // 初始化浏览按钮事件
        browseButton.setOnAction(event -> chooseDirectory());
        // 初始化保存按钮事件
        saveButton.setOnAction(event -> saveConfig());
        executor = Executors.newFixedThreadPool(3);
    }

    /**
     * 保存配置
     */
    private void saveConfig() {
        defaultConfiguration.minDelay = (Double) minDelaySpinner.getValue();
        defaultConfiguration.maxDelay = (Double) maxDelaySpinner.getValue();
        defaultConfiguration.retryDelay = (Double) retryDelaySpinner.getValue();
        defaultConfiguration.maxRetryCount = (Integer) retryCountSpinner.getValue();
        defaultConfiguration.defaultOutputPath = filePathField.getText();
        defaultConfiguration.defaultGenerateMap = defaultMapCheckBox.isSelected();
        defaultConfiguration.defaultDownloadImage = defaultDownloadImageCheckBox.isSelected();
        defaultConfiguration.defaultCommentOrder = commentOrderToggleGroup.getSelectedToggle().equals(likeRadioButton) ? CommentOrder.LIKE.getOrder() : commentOrderToggleGroup.getSelectedToggle().equals(replyRadioButton) ? CommentOrder.REPLY.getOrder() : CommentOrder.TIME.getOrder();
        defaultConfiguration.defaultVideoOrder = videoOrderToggleGroup.getSelectedToggle().equals(publishTimeRadioButton) ? VideoOrder.PUBLISH_TIME.getOrder() : videoOrderToggleGroup.getSelectedToggle().equals(playCountRadioButton) ? VideoOrder.PLAY_COUNT.getOrder() : videoOrderToggleGroup.getSelectedToggle().equals(collectCountRadioButton) ? VideoOrder.COLLECT_COUNT.getOrder() : VideoOrder.PUBLISH_TIME.getOrder();
        defaultConfiguration.emptyPageLimit = (Integer) emptyPageLimitSpinner.getValue();
        defaultConfiguration.cookie = cookieInput.getText();
        defaultConfiguration.saveConfig();
        log.info("保存配置成功");
        // 把当前默认配置的值和对应含义都用日志打印出来
        log.info("配置详情 - 最小延迟: {}秒, 最大延迟: {}秒, 重试延迟: {}秒, 最大重试次数: {}, 空页面限制: {}",
                defaultConfiguration.minDelay, defaultConfiguration.maxDelay,
                defaultConfiguration.retryDelay, defaultConfiguration.maxRetryCount,
                defaultConfiguration.emptyPageLimit);
        log.info("配置详情 - 输出路径: {}, 生成地图: {}, 下载图片: {}, 评论排序: {}, 视频排序: {}",
                defaultConfiguration.defaultOutputPath, defaultConfiguration.defaultGenerateMap,
                defaultConfiguration.defaultDownloadImage, defaultConfiguration.defaultCommentOrder,
                defaultConfiguration.defaultVideoOrder);
    }

    private void initDefaultConfig() {
        defaultOutputPath = defaultConfiguration.defaultOutputPath;
        cookieInput.setText(defaultConfiguration.cookie);
        filePathField.setText(defaultOutputPath);
        defaultMapCheckBox.setSelected(defaultConfiguration.defaultGenerateMap);
        defaultDownloadImageCheckBox.setSelected(defaultConfiguration.defaultDownloadImage);
        minDelaySpinner.getValueFactory().setValue(defaultConfiguration.minDelay);
        maxDelaySpinner.getValueFactory().setValue(defaultConfiguration.maxDelay);
        retryDelaySpinner.getValueFactory().setValue(defaultConfiguration.retryDelay);
        retryCountSpinner.getValueFactory().setValue(defaultConfiguration.maxRetryCount);
        emptyPageLimitSpinner.getValueFactory().setValue(defaultConfiguration.emptyPageLimit);
    }


    /**
     * 显示二维码登录对话框
     */
    private void showQrCodeDialog() {
        // 创建二维码对话框
        qrStage = new Stage();
        qrStage.setTitle("扫码登录");

        // 创建对话框内容
        VBox root = new VBox(10);
        root.setPadding(new Insets(20));
        root.setAlignment(Pos.CENTER);

        qrLabel = new Label("");

        // 二维码显示区域
        ImageView qrImageView = new ImageView();
        qrImageView.setFitWidth(200);
        qrImageView.setFitHeight(200);
        qrImageView.setPreserveRatio(false);

        // 设置示例二维码图片
        try {
            // 从资源目录加载示例二维码图片
            Image qrImage = generateQRCode();
            qrImageView.setImage(qrImage);
            qrLabel.setText("请使用B站APP扫码登录");
        } catch (Exception e) {
            // 如果图片加载失败，显示占位符
            Rectangle placeholder = new Rectangle(200, 200);
            placeholder.setFill(Color.LIGHTGRAY);
            placeholder.setStroke(Color.BLACK);

            Text placeholderText = new Text("二维码区域");
            placeholderText.setFill(Color.GRAY);

            StackPane placeholderPane = new StackPane(placeholder, placeholderText);
            root.getChildren().add(placeholderPane);
            qrLabel.setText("二维码加载失败，点击按钮刷新二维码");
        }

        // 刷新按钮
        Button refreshButton = new Button("刷新二维码");
        refreshButton.setOnAction(e -> refreshQrCode());

        // 添加组件到布局
        root.getChildren().addAll(qrLabel, qrImageView, refreshButton);

        // 设置场景并显示
        Scene scene = new Scene(root, 300, 300);
        qrStage.setScene(scene);
        qrStage.initOwner(primaryStage);
        qrStage.show();


        // 开始轮询
        startPolling();
    }


    private Image generateQRCode() {
//        updateStatusSafe("正在获取二维码...");
        Image fxImage = null;

        try {
            HttpRequest request = HttpRequest.newBuilder()
                    .uri(URI.create("https://passport.bilibili.com/x/passport-login/web/qrcode/generate"))
                    .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
                    .header("Referer", "https://www.bilibili.com/")
                    .header("Origin", "https://www.bilibili.com")
                    .header("Accept", "application/json, text/plain, */*")
                    // HttpRequest会自动处理连接，无需手动设置
//                    .header("Connection", "keep-alive")
                    .timeout(Duration.ofSeconds(10))
                    .GET()
                    .build();

            HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

            if (response.statusCode() != 200) {
                log.info("获取二维码HTTP错误: {}", response.statusCode());
                log.info("响应: {}", response.body());
                return null;
            }


            JSONObject jsonObject = JSON.parseObject(response.body());

            if (!jsonObject.containsKey("data") || !jsonObject.getJSONObject("data").containsKey("url") || !jsonObject.getJSONObject("data").containsKey("qrcode_key")) {
                log.warn("获取二维码失败,response:{}", jsonObject);
                return null;
            }

            JSONObject data = jsonObject.getJSONObject("data");
            // 假设已经获取到url和qrcodeKey
            qrcodeUrl = data.getString("url");
            qrcodeKey = data.getString("qrcode_key");

            log.info("二维码URL: {}...", qrcodeUrl.substring(0, 50));
            log.info("二维码密钥: {}", qrcodeKey);

            // 生成二维码图像
            BufferedImage qrImage = generateQRCodeImage(qrcodeUrl, 200, 200);
//            ImageIcon icon = new ImageIcon(qrImage);
            // 将 BufferedImage 转换为 JavaFX Image
            ByteArrayOutputStream baos = new ByteArrayOutputStream();
            ImageIO.write(qrImage, "png", baos);
            byte[] imageBytes = baos.toByteArray();
            fxImage = new Image(new ByteArrayInputStream(imageBytes));

            return fxImage;

        } catch (Exception e) {
            log.info("生成二维码失败: " + e.getMessage());
//                updateStatusSafe("生成二维码失败，请重试");
        }
        return fxImage;
    }

    private BufferedImage generateQRCodeImage(String content, int width, int height) throws Exception {
        Map<EncodeHintType, Object> hints = new HashMap<>();
        hints.put(EncodeHintType.CHARACTER_SET, "UTF-8");
        hints.put(EncodeHintType.MARGIN, 1);

        BitMatrix bitMatrix = new MultiFormatWriter().encode(content, BarcodeFormat.QR_CODE, width, height, hints);
        return MatrixToImageWriter.toBufferedImage(bitMatrix);
    }

    private void startPolling() {
        if (polling) return;

        polling = true;
        executor.submit(this::pollLoginStatus);
    }

    private void pollLoginStatus() {
        try {
            while (polling && qrcodeKey != null) {
                if (!isDisplayable()) {
                    log.info("对话框已关闭，停止轮询");
                    polling = false;
                    break;
                }

                try {
                    HttpRequest request = HttpRequest.newBuilder()
                            .uri(URI.create("https://passport.bilibili.com/x/passport-login/web/qrcode/poll?qrcode_key=" + qrcodeKey))
                            .header("User-Agent", "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36")
                            .header("Referer", "https://www.bilibili.com/")
                            .header("Origin", "https://www.bilibili.com")
                            .header("Accept", "application/json, text/plain, */*")
//                            .header("Connection", "keep-alive")
                            .timeout(Duration.ofSeconds(10))
                            .GET()
                            .build();

                    HttpResponse<String> response = httpClient.send(request, HttpResponse.BodyHandlers.ofString());

                    if (response.statusCode() != 200) {
                        updateStatusSafe("检查登录状态失败: HTTP " + response.statusCode());
                        log.warn("检查登录状态HTTP错误: {}", response.statusCode());
                        Thread.sleep(2000);
                        continue;
                    }

                    // 解析响应数据并根据code值处理不同情况
                    // 这里省略具体的JSON解析和状态判断逻辑
                    JSONObject responseData;
                    try {
                        String body = response.body();
                        responseData = JSON.parseObject(body);
                    } catch (Exception e) {
                        log.error("解析响应数据异常: {}, 原始响应：{}", e.getMessage(), response.body(), e);
                        Thread.sleep(2000);
                        continue;
                    }

                    if (responseData.getInteger("code") != 0) {
                        updateStatusSafe("登录失败，请重试");
                        log.error("登录失败: {}", StringUtils.isEmpty(responseData.getString("message")) ? "未知错误" : responseData.getString("message"));
                        Thread.sleep(2000);
                        continue;
                    }

                    if (!responseData.containsKey("data") || !responseData.containsKey("code") || !responseData.getJSONObject("data").containsKey("url") ){
                        updateStatusSafe("API响应格式错误");
                        log.error("API响应格式错误");
                        Thread.sleep(2000);
                        continue;
                    }

                    Integer code = responseData.getInteger("code");
                    String message = responseData.getString("message");
                    log.info("登录状态: code={}, message={}", code, message);

                    if (code == 0) {
                        Optional<String> cookieStrOption = response.headers().firstValue("Set-Cookie");
                        log.info("Cookie: {}", cookieStrOption.orElse("null"));
                        if (cookieStrOption.isPresent()) {
                            String cookieStr = cookieStrOption.get();
                            defaultConfiguration.cookie = cookieStr;
                            log.info("Cookie: {}...", cookieStr.substring(0, 50));
                        } else {
                            log.warn("Cookie未找到");
                            Thread.sleep(2000);
                            continue;
                        }
                        onLoginSuccess();
                    }

                    Thread.sleep(1000); // 每秒轮询一次

                } catch (Exception e) {
                    log.error("轮询请求异常: {}", e.getMessage(), e);
                    updateStatusSafe("网络连接异常，重试中...");
                    Thread.sleep(2000);
                }
            }
        } catch (Exception e) {
            log.error("轮询登录状态失败: {}", e.getMessage(), e);
            updateStatusSafe("检查登录状态出错，请重试");
            polling = false;
        }
    }

    private void updateStatusSafe(String s) {
        Platform.runLater(() -> {
            if (!isDisplayable()) return;
            qrLabel.setText(s);
        });
    }


    private boolean isDisplayable() {
        return qrStage.isShowing();
    }

    private void onLoginSuccess() {
        updateStatusSafe("登录成功");
        Platform.runLater(() -> {
            qrStage.close();
            cookieInput.setText(defaultConfiguration.cookie);
        });
        polling = false;
    }

//    private void cancel() {
//        polling = false;
//        if (executor != null && !executor.isShutdown()) {
//            executor.shutdown();
//        }
//        dispose();
//    }
//
//    public String waitForResult() {
//        setVisible(true);
//        return cookie;
//    }

    /**
     * 刷新二维码
     */
    private void refreshQrCode() {
        // TODO: 实现二维码刷新逻辑
        System.out.println("刷新二维码...");
    }

    /**
     * 打开目录选择对话框
     */
    private void chooseDirectory() {
        DirectoryChooser directoryChooser = new DirectoryChooser();
        directoryChooser.setTitle("选择默认输出目录");

        // 设置初始目录（可选）
        defaultOutputPath = filePathField.getText();
        if (defaultOutputPath != null && !defaultOutputPath.isEmpty()) {
            try {
                File initialDir = new File(defaultOutputPath);
                // 检查路径是否为有效目录
                if (initialDir.exists() && initialDir.isDirectory()) {
                    directoryChooser.setInitialDirectory(initialDir);
                } else {
                    // 如果当前路径无效，则使用当前工作目录
                    directoryChooser.setInitialDirectory(new File("."));
                }
            } catch (Exception e) {
                // fallback到当前目录
                directoryChooser.setInitialDirectory(new File("."));
                System.out.println("无法设置初始目录：" + e.getMessage());
            }
        }

        File selectedDirectory = directoryChooser.showDialog(primaryStage);
        if (selectedDirectory != null) {
            defaultOutputPath = selectedDirectory.getAbsolutePath();
            filePathField.setText(defaultOutputPath);
        }
    }

}
